{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FF4NCJVx60-L"
   },
   "source": [
    "<a href=\"https://colab.research.google.com/github/jeffheaton/app_deep_learning/blob/main/assignments/assignment_yourname_class3.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-oNNQ9wq60-N"
   },
   "source": [
    "# T81-558: Applications of Deep Neural Networks\n",
    "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/index.html)\n",
    "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/).\n",
    "\n",
    "**Module 3 Assignment: Simple Classification Neural Network**\n",
    "\n",
    "**Student Name: Your Name**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YxJ7QPBI60-N"
   },
   "source": [
    "# Assignment Instructions\n",
    "\n",
    "For this assignment, you will use the **crx** dataset. You can find the CSV file on my data site, at this location: [crx](https://data.heatonresearch.com/data/t81-558/crx.csv). Load and summarize the data set.  You will submit this summarized dataset to the **submit** function.  See [Assignment #1](https://github.com/jeffheaton/app_deep_learning/blob/main/assignments/assignment_yourname_class1.ipynb) for details on how to submit an assignment or check that one was submitted.\n",
    "\n",
    "The RAW datafile looks something like the following:\n",
    "\n",
    "|a1|a2|s3|a4|a5|a6|a7|a8|a9|a10|a11|a12|a13|a14|a15|a16|\n",
    "|--|--|--|--|--|--|--|--|--|---|---|---|---|---|---|---|\n",
    "|b|30.83|0|u|g|w|v|1.25|t|t|1|f|g|202|0|+|\n",
    "|a|58.67|4.46|u|g|q|h|3.04|t|t|6|f|g|43|560|+|\n",
    "|...|...|...|...|...|...|...|...|...|...|...|...|...|...|...|...|\n",
    "\n",
    "For this assignment you must complete the following.\n",
    "\n",
    "* Write a classification neural network that predicts the probability of either \"+\" or \"-\" for the column **a16**.\n",
    "* Use early stopping to know when to complete your training.\n",
    "* For all columns that are categorical, you must convert them to dummy variables.\n",
    "* Some columns have missing values, fill these missing values with the median of that column.\n",
    "* This is a simple neural network using basic techniques, do not worry too much about overall accuracy.\n",
    "* Predict/submit for the entire dataset that I gave you, training and validation, you should have the same number of rows as crx.csv (690 data and 1 header row).\n",
    "\n",
    "Your submit will look something like the following:\n",
    "\n",
    "|+|-|\n",
    "|-|-|\n",
    "|0.09405358|0.90594643|\n",
    "|0.33253232|0.66746765|\n",
    "|0.098494485|0.90150553|\n",
    "|...|...|\n",
    "\n",
    "Common errors that you may run into include:\n",
    "\n",
    "* **ValueError: could not convert string to float: ...** - Value errors typically mean you've not converted all of the categoricals to dummy variables.\n",
    "\n",
    "* **tloss nan:** - Nan's usually mean youve not filled all missing values.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Tj3VFPa660-O"
   },
   "source": [
    "# Google CoLab Instructions\n",
    "\n",
    "If you are using Google CoLab, it will be necessary to mount your GDrive so that you can send your notebook during the submit process. Running the following code will map your GDrive to ```/content/drive```."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "8fkC2nit60-O",
    "outputId": "1f1a40fa-0ae4-4ab9-917a-0ab35b0c34c2"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from google.colab import drive\n",
    "    drive.mount('/content/drive', force_remount=True)\n",
    "    COLAB = True\n",
    "    print(\"Note: using Google CoLab\")\n",
    "except:\n",
    "    print(\"Note: not using Google CoLab\")\n",
    "    COLAB = False\n",
    "\n",
    "# Early stopping (see module 3.4)\n",
    "import copy\n",
    "\n",
    "class EarlyStopping:\n",
    "    def __init__(self, patience=5, min_delta=0, restore_best_weights=True):\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.restore_best_weights = restore_best_weights\n",
    "        self.best_model = None\n",
    "        self.best_loss = None\n",
    "        self.counter = 0\n",
    "        self.status = \"\"\n",
    "\n",
    "    def __call__(self, model, val_loss):\n",
    "        if self.best_loss is None:\n",
    "            self.best_loss = val_loss\n",
    "            self.best_model = copy.deepcopy(model.state_dict())\n",
    "        elif self.best_loss - val_loss >= self.min_delta:\n",
    "            self.best_model = copy.deepcopy(model.state_dict())\n",
    "            self.best_loss = val_loss\n",
    "            self.counter = 0\n",
    "            self.status = f\"Improvement found, counter reset to {self.counter}\"\n",
    "        else:\n",
    "            self.counter += 1\n",
    "            self.status = f\"No improvement in the last {self.counter} epochs\"\n",
    "            if self.counter >= self.patience:\n",
    "                self.status = f\"Early stopping triggered after {self.counter} epochs.\"\n",
    "                if self.restore_best_weights:\n",
    "                    model.load_state_dict(self.best_model)\n",
    "                return True\n",
    "        return False\n",
    "\n",
    "# Make use of a GPU or MPS (Apple) if one is available.  (see module 3.2)\n",
    "import torch\n",
    "\n",
    "device = (\n",
    "    \"mps\"\n",
    "    if getattr(torch, \"has_mps\", False)\n",
    "    else \"cuda\"\n",
    "    if torch.cuda.is_available()\n",
    "    else \"cpu\"\n",
    ")\n",
    "print(f\"Using device: {device}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "w_LSlw3Q60-O"
   },
   "source": [
    "# Assignment Submit Function\n",
    "\n",
    "You will submit the 10 programming assignments electronically.  The following submit function can be used to do this.  My server will perform a basic check of each assignment and let you know if it sees any basic problems.\n",
    "\n",
    "**It is unlikely that should need to modify this function.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "PjtiWqCU60-O"
   },
   "outputs": [],
   "source": [
    "import base64\n",
    "import os\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import requests\n",
    "import PIL\n",
    "import PIL.Image\n",
    "import io\n",
    "\n",
    "# This function submits an assignment.  You can submit an assignment as much as you like, only the final\n",
    "# submission counts.  The paramaters are as follows:\n",
    "# data - List of pandas dataframes or images.\n",
    "# key - Your student key that was emailed to you.\n",
    "# no - The assignment class number, should be 1 through 1.\n",
    "# source_file - The full path to your Python or IPYNB file.  This must have \"_class1\" as part of its name.\n",
    "# .             The number must match your assignment number.  For example \"_class2\" for class assignment #2.\n",
    "def submit(data,key,no,source_file=None):\n",
    "    if source_file is None and '__file__' not in globals(): raise Exception('Must specify a filename when a Jupyter notebook.')\n",
    "    if source_file is None: source_file = __file__\n",
    "    suffix = '_class{}'.format(no)\n",
    "    if suffix not in source_file: raise Exception('{} must be part of the filename.'.format(suffix))\n",
    "    with open(source_file, \"rb\") as image_file:\n",
    "        encoded_python = base64.b64encode(image_file.read()).decode('ascii')\n",
    "    ext = os.path.splitext(source_file)[-1].lower()\n",
    "    if ext not in ['.ipynb','.py']: raise Exception(\"Source file is {} must be .py or .ipynb\".format(ext))\n",
    "    payload = []\n",
    "    for item in data:\n",
    "        if type(item) is PIL.Image.Image:\n",
    "            buffered = BytesIO()\n",
    "            item.save(buffered, format=\"PNG\")\n",
    "            payload.append({'PNG':base64.b64encode(buffered.getvalue()).decode('ascii')})\n",
    "        elif type(item) is pd.core.frame.DataFrame:\n",
    "            payload.append({'CSV':base64.b64encode(item.to_csv(index=False).encode('ascii')).decode(\"ascii\")})\n",
    "    r= requests.post(\"https://api.heatonresearch.com/assignment-submit\",\n",
    "        headers={'x-api-key':key}, json={ 'payload': payload,'assignment': no, 'ext':ext, 'py':encoded_python})\n",
    "    if r.status_code==200:\n",
    "        print(\"Success: {}\".format(r.text))\n",
    "    else: print(\"Failure: {}\".format(r.text))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "id": "kTp6GZt860-P"
   },
   "source": [
    "# Assignment #3 Sample Code\n",
    "\n",
    "The following code provides a starting point for this assignment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "P2DxMbVI60-P",
    "outputId": "9b14f90b-8a8d-4236-ccaf-031b7ca2a857"
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import pandas as pd\n",
    "from scipy.stats import zscore\n",
    "import numpy as np\n",
    "import torch\n",
    "import tqdm\n",
    "from sklearn.metrics import accuracy_score\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelEncoder, StandardScaler\n",
    "from torch import nn\n",
    "from torch.autograd import Variable\n",
    "from torch.utils.data import DataLoader, TensorDataset\n",
    "\n",
    "\n",
    "# This is your student key that I emailed to you at the beginnning of the semester.\n",
    "key = \"Gx5en9cEVvaZnjut6vfLm1HG4ZO4PsI32sgldAXj\"  # This is an example key and will not work.\n",
    "\n",
    "# You must also identify your source file.  (modify for your local setup)\n",
    "file='/content/drive/My Drive/Colab Notebooks/c_assignment_yourname_class3.ipynb'  # Google CoLab\n",
    "# file='C:\\\\Users\\\\jeffh\\\\projects\\\\t81_558_deep_learning\\\\assignments\\\\assignment_yourname_class3.ipynb'  # Windows\n",
    "# file='/Users/jheaton/projects/t81_558_deep_learning/assignments/assignment_yourname_class3.ipynb'  # Mac/Linux\n",
    "\n",
    "# Begin assignment\n",
    "\n",
    "df = pd.read_csv(\"https://data.heatonresearch.com/data/t81-558/crx.csv\",na_values=['?'])\n",
    "\n",
    "# Your code goes here.\n",
    "\n",
    "# Submit it\n",
    "submit(source_file=file,data=[df_submit],key=key,no=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "i5SDmZYd60-P"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3.9 (torch)",
   "language": "python",
   "name": "pytorch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
